package com.physics.mps.common.config.auth;

import cn.hutool.core.util.IdUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import com.physics.mps.common.config.constant.JWTConstants;
import com.physics.mps.common.config.constant.TokenConstants;
import com.physics.mps.common.config.properties.TokenProperties;
import com.physics.mps.entity.vo.login.LoginVo;
import com.physics.mps.entity.vo.login.TokenVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author mcsoft
 * @date 2023/8/28 14:51
 */
@Log4j2
@RequiredArgsConstructor
@Component
public class TokenHandler {


    private final RedisTemplate<Object, Object> redisTemplate;

    private final TokenProperties tokenProperties;


    /**
     * 创建token
     *
     * @param loginVo
     * @return
     */
    public TokenVo createToken(LoginVo loginVo) {
        String token = IdUtil.fastUUID();
        int userId = loginVo.getId();
        String userName = loginVo.getUsername();
        loginVo.setToken(token);

        refreshToken(loginVo);

        // Jwt存储信息
        Map<String, Object> claimsMap = new HashMap<String, Object>();
        claimsMap.put(JWTConstants.KEY, token);
        claimsMap.put(JWTConstants.USER_ID, userId);
        claimsMap.put(JWTConstants.USERNAME, userName);
        return new TokenVo(JWTUtil.createToken(claimsMap, TokenConstants.SECRET.getBytes()), loginVo.getExpireTime());
    }


    /**
     * 登录信息缓存到redis
     *
     * @param loginVo
     */
    public void refreshToken(LoginVo loginVo) {
        loginVo.setLoginTime(System.currentTimeMillis());
        loginVo.setExpireTime(loginVo.getLoginTime() + tokenProperties.getAccessExpire() * 1000);
        // 根据uuid将loginUser缓存
        String tokenKey = getTokenKey(loginVo.getToken());
        redisTemplate.opsForValue().set(tokenKey, loginVo, tokenProperties.getAccessExpire(), TimeUnit.SECONDS);
    }


//    /**
//     * 刷新token过期时间
//     *
//     * @param token
//     */
//    public void expireToken(String token) {
//        cacheExecutorService.submit(() -> {
//            String tokenKey = getTokenKey(token);
//            long expire = getTokenKeyExpire(token);
//            // 超过阈值自动续期
//            if (expire > 0 && expire > tokenProperties.getAccessExpire() * tokenProperties.getRefreshExpireFactor()) {
//                return;
//            }
//            redisTemplate.expire(tokenKey, tokenProperties.getAccessExpire(), TimeUnit.SECONDS);
//            log.info("tokenKey:{},before:{},after:{}", tokenKey, expire, getTokenKeyExpire(token));
//        });
//    }


    /**
     * redis token key
     *
     * @param token
     * @return
     */
    private String getTokenKey(String token) {
        return TokenConstants.TOKEN_KEY + token;
    }


    /**
     * 判断token是否过期
     *
     * @param token
     * @return
     */
    public boolean isExpire(String token) {
        JWT jwt = JWTUtil.parseToken(token);
        String tokenKey = jwt.getPayload(JWTConstants.KEY).toString();
        return getTokenKeyExpire(tokenKey) > 0;
    }


    /**
     * 判断tokenKey是否过期
     *
     * @param tokenKey
     * @return
     */
    public boolean isExpireTokenKey(String tokenKey) {
        return getTokenKeyExpire(tokenKey) > 0;
    }


    /**
     * 获取key的过期时间
     *
     * @param token
     * @return
     */
    public long getTokenKeyExpire(String token) {
        Long expire = redisTemplate.getExpire(getTokenKey(token));
        expire = null == expire ? -1L : expire;
        log.info("tokenKey:{},expire;{}", getTokenKey(token), expire);
        return expire;
    }


    /**
     * 销毁Token
     *
     * @param token
     */
    public void destroyToken(String token) {
        if (null == token) {
            return;
        }
        JWT jwt = JWTUtil.parseToken(token);
        String tokenKey = jwt.getPayload(JWTConstants.KEY).toString();
        redisTemplate.delete(getTokenKey(tokenKey));
        log.info("销毁token：{}", token);
    }


}
